﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
using AGPR.Locadora.Data;
using AGPR.Locadora.Utils;

namespace AGPR.Locadora.Model
{
    /// <summary>
    /// Classe de Cliente que extende a Classe Abstrata Pessoa
    /// </summary>
    public class Cliente : Pessoa
    {
        private static ActiveRecord db = ActiveRecord.Instancia;

        #region Atributos

        /// <summary>
        /// Nome da Tabela no Banco de Dados
        /// </summary>
        const string TABELA = "cliente";
        const string VIEW = "vw_cliente";
        
        /// <summary>
        /// Código do Cliente
        /// </summary>
        [Display(Name = "Código do Cliente")]
        public int id { get; set; }

        /// <summary>
        /// Anotações 
        /// </summary>
        [Display(Name = "Anotações")]
        public string anotacoes { get; set; }

        /// <summary>
        /// Data de Cadastro do Cliente
        /// </summary>
        [Display(Name = "Data de Cadastro")]
        public DateTime data_cadastro { get; set; }

        /// <summary>
        /// Telefone Fixo
        /// </summary>
        [Display(Name = "Telefone Fixo")]
        public string telefone_fixo { get; set; }

        /// <summary>
        /// Telefone Móvel
        /// </summary>
        [Display(Name = "Telefone Móvel")]
        public string telefone_movel { get; set; }

        #endregion

        #region Create

        /// <summary>
        /// Retorna uma instância de Cliente populada
        /// </summary>
        /// <param name="dados">Dados</param>
        /// <returns></returns>
        public static Cliente Create(dynamic dados = null)
        {
            Cliente cliente = new Cliente();

            if (dados != null)
            {
                cliente.id = Convert.ToInt32(dados["id_cliente"]);
                cliente.id_endereco = Convert.ToInt32(dados["id_endereco"]);
                cliente.endereco = Endereco.Create(dados);
                cliente.nome = dados["nome"];
                cliente.cpf = dados["cpf"];
                cliente.email = dados["email"];
                cliente.telefone_fixo = dados["telefone_fixo"];
                cliente.telefone_movel = dados["telefone_movel"];
                cliente.sexo = dados["sexo"];
                cliente.anotacoes = dados["anotacoes"];
                cliente.data_nascimento = dados["data_nascimento"];
                cliente.data_cadastro = Convert.ToDateTime(dados["data_cadastro"]);
                cliente.ativoCheckbox = dados["ativo"];
            }

            return cliente;
        }

        #endregion

        #region getNextID

        /// <summary>
        /// Retorna o Proximo ID
        /// </summary>
        /// <returns>ID</returns>
        private int getNextID()
        {
            return db.max("id_cliente", TABELA) + 1;
        }

        #endregion

        #region Cadastrar

        /// <summary>
        /// Cadastra o Cliente no Banco de Dados
        /// </summary>
        /// <returns>Cliente</returns>
        public Cliente Cadastrar()
        {
            this.id = this.id > 0 ? this.id : this.getNextID();

            this.endereco.Cadastrar();
            this.id_endereco = this.endereco.id;

            db.insert(TABELA, new Dictionary<string, dynamic>
            {
                {"id_cliente", this.id},
                {"id_endereco", this.id_endereco},
                {"nome", this.nome},
                {"cpf", Format.limparNumero(this.cpf)},
                {"email", this.email},
                {"sexo", this.sexo},
                {"anotacoes", this.anotacoes},
                {"telefone_fixo", this.telefone_fixo},
                {"telefone_movel", this.telefone_movel},
                {"data_nascimento", this.data_nascimento},
                {"ativo", this.ativo}
            });

            return this;
        }

        #endregion

        #region Alterar

        /// <summary>
        /// Altera o Cliente no Banco de Dados
        /// </summary>
        /// <returns>Cliente</returns>
        public Cliente Alterar()
        {
            if (this.id > 0)
            {
                this.endereco.Alterar();

                db.where("id_cliente", this.id);
                db.update(TABELA, new Dictionary<string, dynamic>
                {
                    {"nome", this.nome},
                    {"cpf", Format.limparNumero(this.cpf)},
                    {"sexo", this.sexo},
                    {"email", this.email},
                    {"anotacoes", this.anotacoes},
                    {"telefone_fixo", this.telefone_fixo},
                    {"telefone_movel", this.telefone_movel},
                    {"data_nascimento", this.data_nascimento},
                    {"ativo", this.ativo}
                });
            }

            return this;
        }

        #endregion

        #region Excluir

        /// <summary>
        /// Exclui um Cliente da base de dados
        /// </summary>
        /// <returns>Cliente</returns>
        public Cliente Excluir()
        {
            if (this.id > 0)
            {
                // Só excluo se não tiver nenhuma locação
                if (this.TotalLocacoes() == 0)
                {
                    db.startTransaction();
                    db.where("id_cliente", this.id).delete(TABELA);
                    db.where("id_endereco", this.id_endereco).delete(Endereco.TABELA);
                    db.commit();
                }
            }

            return this;
        }

        #endregion

        #region Get

        /// <summary>
        /// Retorna um Cliente pelo ID
        /// </summary>
        /// <param name="id">ID do Cliente</param>
        /// <returns>Cliente</returns>
        public static Cliente Get(dynamic id)
        {
            var cliente = db.where("id_cliente", id).selectOne(VIEW);

            return cliente != null ? Cliente.Create(cliente) : null;
        }

        /// <summary>
        /// Retorna uma lista de todos Clientes
        /// </summary>
        /// <returns>Lista de Clientes</returns>
        public static List<Cliente> GetAll(int offset = 0)
        {
            List<Cliente> clientes = new List<Cliente>();

            db.order_by("nome").limit(offset, Config.PageLimit);

            foreach (var cliente in db.select(VIEW))
            {
                clientes.Add(Cliente.Create(cliente));
            }

            return clientes;
        }

        #endregion

        #region Pesquisar

        /// <summary>
        /// Retorna os Clientes de acordo com a query
        /// </summary>
        /// <param name="query">query</param>
        /// <returns>Clientes</returns>
        public static List<Cliente> Pesquisar(string query)
        {
            db.like("nome", query);

            return GetAll();
        }

        #endregion

        #region Total

        /// <summary>
        /// Retorna o Total de Clientes Cadastrados
        /// </summary>
        /// <returns>Total</returns>
        public static int Total()
        {
            return db.count(VIEW);
        }

        #endregion

        #region TotalLocacoes

        /// <summary>
        /// Retorna o Total de Locações deste Clientes
        /// </summary>
        /// <returns>Total</returns>
        public int TotalLocacoes()
        {
            db.where("id_cliente", this.id);
            return db.count(Locacao.TABELA);
        }

        #endregion
    }
}
